package com.ygq.controller;

import BO.BackBO;
import BO.JavaRunBO;
import VO.EncodeJudgeVO;
import com.ygq.EncodeQuestionService;
import com.ygq.PublishTestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import result.Result;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/student")
public class RunController {

    @Value("${ygq.encode-path}")
    private String path;

    @Value("${ygq.url}")
    private String url;

    @Autowired
    private PublishTestService publishTestService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private EncodeQuestionService encodeQuestionService;

    /**
     * 编程题判断接口
     * @param file java文件，文件名就是主类名称
     * @param encodeId 编程题id
     * @param userId 用户id
     * @return 返回是否正确以及编译，运行时间或者错误信息
     */
    @PostMapping("/javaRun")
    public Result<EncodeJudgeVO> saveFile(MultipartFile file, Integer encodeId, Integer userId) throws IOException {

        EncodeJudgeVO encodeJudgeVO = new EncodeJudgeVO();
        encodeJudgeVO.setEncodeId(encodeId);
        String filename = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."));

        // 构建新文件名 原文件名+用户id+编程题id
        String NewFileName = filename + "-" + userId + "-" + encodeId + ".txt";

        // 将文件内容读取到一个字符串中
        String code = new String(file.getBytes());

        // 将学生做的文件保存到服务器端
        saveFile(file,path,NewFileName);
        List<JavaRunBO> javaRunBOList = publishTestService.encodeJudge(userId, encodeId, filename);

        // 设置平均运行和编译时间,这里存储总的数据
        Long compileTime = 0L;
        Long runTime = 0L;
        if (javaRunBOList.size()==0){
            EncodeJudgeVO encodeJudgeVO1 = new EncodeJudgeVO();
            encodeJudgeVO1.setState(8);
            encodeJudgeVO1.setMessage("该题目没有设置测试用例，请联系老师修正");
            encodeJudgeVO1.setEncodeId(encodeId);
            return Result.success(encodeJudgeVO1);
        }
        // 发起远程调用
        for (JavaRunBO javaRunBO : javaRunBOList) {
            //  这里发起远程调用
            Map map = new HashMap();
            map.put("code",code);
            map.put("input",javaRunBO.getInput());
            map.put("logo",javaRunBO.getLogo());
            map.put("className",filename);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(map, headers);
            BackBO backBO = restTemplate.postForObject(url, requestEntity, BackBO.class);
            // 总时间
            if (backBO.getCompileTime() != null) {
                compileTime = compileTime + backBO.getCompileTime();
            }
            if (backBO.getRunTime() != null) {
                runTime = runTime + backBO.getRunTime();
            }
            if (backBO.getState() == 0){
                // 表示运行成功，接下来判断输出结果是否满足,这个输出信息的字符串是使用 /n 作为行替换符
                String message = backBO.getMessage();
                String[] output = message.split("\n");
                String[] output1 = javaRunBO.getOutput();
                // 可以正常运行，但是输出结果的行数不正确
                if (output1.length != output.length){
                    encodeJudgeVO.setMessage("理想输出:\n" + String.join(System.lineSeparator(),output1) + "\n" + "你的输出:\n" + String.join(System.lineSeparator(),output));
                    encodeJudgeVO.setRunTime(backBO.getRunTime());
                    encodeJudgeVO.setCompileTime(backBO.getCompileTime());
                    encodeJudgeVO.setState(5);
                    encodeQuestionService.editMinus(encodeId);
                    return Result.success(encodeJudgeVO);
                }
                for (int i = 0; i < output.length; i++) {
                    if (!output1[i].equals(output[i])){
                        String messageTO = "理想输出:\n";
                        for (String s : output1) {
                            messageTO = messageTO + s + "\n";
                        }
                        messageTO = messageTO + "你的输出:\n";
                        for (String s : output) {
                            messageTO = messageTO + s + "\n";
                        }
                        encodeJudgeVO.setMessage(messageTO);
                        encodeJudgeVO.setRunTime(backBO.getRunTime());
                        encodeJudgeVO.setCompileTime(backBO.getCompileTime());
                        encodeJudgeVO.setState(5);
                        encodeQuestionService.editMinus(encodeId);
                        return Result.success(encodeJudgeVO);
                    }
                }

            }
            else if (backBO.getState() == 1){
                // 1表示运行失败
                encodeQuestionService.editMinus(encodeId);
                encodeJudgeVO.setState(1);
                encodeJudgeVO.setMessage(backBO.getMessage());
                encodeJudgeVO.setCompileTime(backBO.getCompileTime());
                return Result.success(encodeJudgeVO);
            }
            else if (backBO.getState() == 2){
                // 2表示编译失败
                encodeQuestionService.editMinus(encodeId);
                encodeJudgeVO.setState(2);
                encodeJudgeVO.setMessage(backBO.getMessage());
                return Result.success(encodeJudgeVO);
            }
            else if (backBO.getState() == 3){
                // 3表示运行时间超出限制，可能是因为死循环
                encodeQuestionService.editMinus(encodeId);
                encodeJudgeVO.setState(3);
                encodeJudgeVO.setMessage(backBO.getMessage());
                encodeJudgeVO.setCompileTime(backBO.getCompileTime());
                return Result.success(encodeJudgeVO);
            }
            else if (backBO.getState() == 4){
                // 4表示运行时发送io异常，需要进行处理
                encodeJudgeVO.setState(4);
                encodeJudgeVO.setMessage("网络错误，请联系管理员");
                return Result.success(encodeJudgeVO);
            }

        }

        // 表示每一次都运行成功，且输出结果都正确，就不需要像前端返回message，只需要返回编译，运行时间即可
        encodeQuestionService.editAdd1(encodeId);
        encodeJudgeVO.setState(0);
        encodeJudgeVO.setRunTime(runTime/javaRunBOList.size());
        encodeJudgeVO.setCompileTime(compileTime/javaRunBOList.size());
        System.out.println(encodeJudgeVO);
        return Result.success(encodeJudgeVO);
    }


    // 保存文件的方法
    public void saveFile(MultipartFile file, String filePath, String newFileName) {
        try {
            byte[] bytes = file.getBytes();
            Path path = Paths.get(filePath + File.separator + newFileName);
            Files.write(path, bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
